/*
 * Copyright (C) 2013 gujicheng
 * 
 * Licensed under the GPL License Version 2.0;
 * you may not use this file except in compliance with the License.
 * 
 * If you have any question, please contact me.
 * 
 *************************************************************************
 **                   Author information                                **
 *************************************************************************
 ** Email: gujicheng197@126.com                                         **
 ** QQ   : 29600731                                                     **
 ** Weibo: http://weibo.com/gujicheng197                                **
 *************************************************************************
 */
package com.libra.sinvoice

import java.util.ArrayList

import android.media.AudioFormat
import android.text.TextUtils

import com.libra.sinvoice.Buffer.BufferData

/**
 *
 * @ClassName: com.libra.sinvoice.SinVoicePlayer
 * @Description: 声音播放类
 * @author zhaokaiqiang
 * @date 2014-11-15 下午12:56:57
 */
class SinVoicePlayer
/**
 * 构造函数
 *
 * @param codeBook
 * @param sampleRate
 * 采样率
 * @param bufferSize
 * 缓冲区体积
 * @param buffCount
 * 缓冲区数量
 */
@JvmOverloads constructor(codeBook: String = Common.CODE_BOOK, sampleRate: Int = Common.DEFAULT_SAMPLE_RATE, bufferSize: Int = Common.DEFAULT_BUFFER_SIZE,
                          buffCount: Int = Common.DEFAULT_BUFFER_COUNT) : Encoder.EncoderCallback, PcmPlayer.PcmListener, PcmPlayer.PcmCallback {

    private var mCodeBook: String? = null
    // 用于存放使用CoodBook编码过的数字
    private val mCodes = ArrayList<Int>()

    private val mEncoder: Encoder
    private val pcmPlayer: PcmPlayer
    private val mBuffer: Buffer

    private var mState: Int = 0
    private var mListener: Listener? = null
    private var mPlayThread: Thread? = null
    private var mEncodeThread: Thread? = null

    override val encodeBuffer: BufferData?
        get() = mBuffer.empty

    interface Listener {

        fun onPlayStart()

        fun onPlayEnd()
    }

    init {
        mState = STATE_STOP
        mBuffer = Buffer(buffCount, bufferSize)

        mEncoder = Encoder(this, sampleRate, SinGenerator.BITS_16, bufferSize)
        pcmPlayer = PcmPlayer(this, sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize)
        pcmPlayer.setListener(this)
        setCodeBook(codeBook)
        Common.init()
    }

    fun setListener(listener: Listener) {
        mListener = listener
    }

    fun setCodeBook(codeBook: String) {
        if (!TextUtils.isEmpty(codeBook) && codeBook.length < Encoder.maxCodeCount - 1) {
            mCodeBook = codeBook
        }
    }

    /**
     * 将要加密的文本根据CodeBook进行编码
     *
     * @param text
     * @return 是否编码成功
     */
    private fun convertTextToCodes(text: String?): Boolean {
        var text = text
        var ret = true

        if (!TextUtils.isEmpty(text)) {
            mCodes.clear()
            mCodes.add(Common.START_TOKEN)
            text = encodeText(text)
            val len = text!!.length
            for (i in 0 until len) {
                val ch = text[i]
                val index = mCodeBook!!.indexOf(ch)
                if (index > -1) {
                    mCodes.add(index + 1)
                } else {
                    ret = false
                    LogHelper.d(TAG, "invalidate char:$ch")
                    break
                }
            }
            if (ret) {
                mCodes.add(Common.STOP_TOKEN)
            }
        } else {
            ret = false
        }

        return ret
    }

    private fun encodeText(text: String?): String? {
        val sb = StringBuilder()
        text?.forEach { x -> sb.append(Common.CODE_MAP[x]) }
        return sb.toString()
    }

    fun play(text: String) {
        if (STATE_STOP == mState && null != mCodeBook
                && convertTextToCodes(text)) {
            mState = STATE_PENDING

            mPlayThread = object : Thread() {
                override fun run() {
                    pcmPlayer.start()
                }
            }

            if (null != mPlayThread) {
                mPlayThread!!.start()
            }

            mEncodeThread = object : Thread() {
                override fun run() {
                    mEncoder.encode(mCodes, DEFAULT_GEN_DURATION)
                    stopPlayer()
                    mEncoder.stop()
                    pcmPlayer.stop()
                }
            }
            if (null != mEncodeThread) {
                mEncodeThread!!.start()
            }

            mState = STATE_START
        }
    }

    fun stop() {
        if (STATE_START == mState) {
            mState = STATE_PENDING
            mEncoder.stop()
            if (null != mEncodeThread) {
                try {
                    mEncodeThread!!.join()
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                } finally {
                    mEncodeThread = null
                }
            }

        }
    }

    private fun stopPlayer() {
        if (mEncoder.isStoped) {
            pcmPlayer.stop()
        }

        // put end buffer
        mBuffer.putFull(BufferData.emptyBuffer)

        if (null != mPlayThread) {
            try {
                mPlayThread!!.join()
            } catch (e: InterruptedException) {
                e.printStackTrace()
            } finally {
                mPlayThread = null
            }
        }

        mBuffer.reset()
        mState = STATE_STOP
    }

    override fun freeEncodeBuffer(buffer: BufferData) {
        if (null != buffer) {
            mBuffer.putFull(buffer)
        }
    }

    override fun getPcmPlayBuffer(): BufferData? {
        // 获取播放资源
        return mBuffer.full
    }

    override fun freePcmPlayData(data: BufferData) {
        // 释放播放资源
        mBuffer.putEmpty(data)
    }

    override fun onPcmPlayStart() {
        if (null != mListener) {
            mListener!!.onPlayStart()
        }
    }

    override fun onPcmPlayStop() {
        if (null != mListener) {
            mListener!!.onPlayEnd()
        }
    }

    companion object {

        private val TAG = "SinVoicePlayer"

        private val STATE_START = 1
        private val STATE_STOP = 2
        private val STATE_PENDING = 3

        // 默认的持续时间
        private val DEFAULT_GEN_DURATION = 100
    }

}
